"""
Created on 30-Jul-2009

@author: dexen
"""


class QManager(object):
    """Class
    A class for managing the assignment of partially-processed individuals
    to queues.
    
    """
    def __init__(self, queues, qlocks, scripts_info, pop_mgr):
        """Constructor
        
        Args:
        queues : A dict that stores the queues of type multiprocessing.Queue.
        Each queue is referenced by the name of a script to which it belongs.
        
        scripts_info : A dict that stores all of the scripts properties set in
        the config.py file. Each script info -of type dict- is referenced by 
        its name.
        
        pop_mgr : Refers to a PopManager object. It is used to get and set 
        actual data in the in-memory database (inds_db)  
        
        """
        self.queues = queues
        self.qlocks = qlocks
        
        print "qlocks in Qmanager"
        print self.qlocks
        self.scripts_info = scripts_info
        self.pop_mgr = pop_mgr
    
    def __repr__(self):
        res = "Queue State\n"
        for iq_name, item in self.queues.items():
            res += "%s: %s\n" %(iq_name, item.qsize()) 
        return res
    
    def get_inds(self):
        """Get individuals from the first queue found to have enough inds.
        
        Returns a tuple consisting of two elements. The first element refers to
        the name of the queue from which the individuals were pulled. The second 
        holds the list of individuals to be sent off to a slave.
        
        """
        while True:
            for input_qname in self.queues.keys():
                lock = self.qlocks[input_qname] 
                queue = self.queues[input_qname]
                script_info = self.scripts_info[input_qname] 
                cnt = script_info["input_size"]
                if cnt is None: cnt = 999
                ids = []
                lock.acquire()
                if queue.qsize() >= cnt:
                    for _ in range(cnt):
                        ids.append(queue.get())
                    lock.release()
                    inds = self.pop_mgr.get_individuals(input_qname, ids)
                    return input_qname, inds
                lock.release()
    
    def set_inds(self, script_name, inds):
        """Put the individuals into the in-memory database (ind_db).
        
        After updating and inserting individuals in ind_db. It will place the 
        individuals into respective queues. The placement is determined by 
        pop_mgr in the form of queue_name and list of ids for it.
    
        Returns None for the moment.
        """
        res = self.pop_mgr.set_individuals(inds)
        for q_name, ids in res.items():
            if ids == []: continue
            self.qlocks[q_name].acquire()
            for id in ids:
                self.queues[q_name].put(id)            
            self.qlocks[q_name].release()
        return None
    
    def recover_inds(self, inds, iq_name):
        self.qlocks[iq_name].acquire()
        for ind in inds:
            self.queues[iq_name].put(ind.__id__)
        self.qlocks[iq_name].release()
        
